from rest_framework import serializers
from . import models
from rest_framework.exceptions import ValidationError
from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler
from django.conf import settings
from django.core.cache import cache
import re
from rest_framework import exceptions


class LoginSerialzer(serializers.ModelSerializer):
    username = serializers.CharField()  # 数据库中唯一字段

    class Meta:
        model = models.User
        fields = ['id', 'username', 'icon', 'password']
        extra_kwargs = {
            'password': {'write_only': True},
            'username': {'write_only': True},
        }

    def _get_user(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        # 判断username是手机，邮箱，用户名
        import re
        if re.match(r'^1[3-9][0-9]{9}$', username):
            # 手机登录
            user = models.User.objects.filter(mobile=username, is_active=True).first()
        elif re.match(r'^.+@.+$', username):
            # 邮箱登录
            user = models.User.objects.filter(email=username, is_active=True).first()
        else:
            # 账号登录
            user = models.User.objects.filter(username=username, is_active=True).first()
        if user and user.check_password(password):  # 校验密码
            return user
        raise ValidationError('用户名或密码错误')

    def _get_token(self, user):
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token

    def validate(self, attrs):
        # 校验逻辑写在这里面
        user = self._get_user(attrs)
        # 通过请求头格式化icon
        request = self.context['request']
        # request.META['HTTP_HOST']:服务器地址
        icon = 'http://%s%s%s' % (request.META['HTTP_HOST'], settings.MEDIA_URL, user.icon)
        # icon:http://127.0.0.1:8000/media/icon/default.png

        token = self._get_token(user)
        self.context['token'] = token
        self.context['user'] = user
        self.context['icon'] = icon
        return attrs


class LoginCodeSerialzer(serializers.ModelSerializer):
    mobile = serializers.CharField()  # 重写该字段
    code = serializers.CharField()

    class Meta:
        model = models.User
        fields = ['mobile', 'code']

    # 局部钩子，验证手机号是否合法
    # 手机号格式校验（手机号是否存在校验规则自己考量）
    def validate_mobile(self, value):
        if not re.match(r'^1[3-9][0-9]{9}$', value):
            raise exceptions.ValidationError('mobile field error')
        return value

    # 全局钩子

    def _check_code(self, attrs):
        mobile = attrs.get('mobile')
        code_in = attrs.get('code')
        code = cache.get(settings.SMS_CACHE_KEY % {'mobile': mobile})
        # 开发测试阶段可能会留的，万能验证码
        if code_in == code or code_in == '1234':
            return mobile
        else:
            raise exceptions.ValidationError('验证码不合法')

    def _get_user(self, mobile):
        user = models.User.objects.filter(mobile=mobile, is_active=True).first()
        if user:
            return user
        else:
            raise exceptions.ValidationError('手机号不存在')

    def _get_token(self, user):
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token

    def validate(self, attrs):
        # 通过手机号获取用户
        # 比较验证码是否一致
        # 签发token
        request = self.context.get('request')
        # 验证码校验 - 需要验证码与手机号两者参与
        mobile = self._check_code(attrs)
        # 多方式得到user
        user = self._get_user(mobile)
        # user签发token
        token = self._get_token(user)
        # token用context属性携带给视图类
        self.context['token'] = token
        # 将登录用户对象直接传给视图
        self.context['user'] = user
        icon = 'http://%s%s%s' % (request.META['HTTP_HOST'], settings.MEDIA_URL, user.icon)
        self.context['icon'] = icon
        return attrs


class CodeRegisterSerializer(serializers.ModelSerializer):
    code = serializers.CharField(write_only=True)

    class Meta:
        model = models.User
        fields = ['username', 'mobile', 'code', 'password']
        extra_kwargs = {

            'password': {'write_only': True},
            'username': {'read_only': True}
        }

    def validate(self, attrs):
        # 手机号是否合法，是否存在
        mobile = attrs.get('mobile')
        code_in = attrs.get('code')
        if re.match(r'^1[3-9][0-9]{9}$', mobile):
            # user = models.User.objects.filter(mobile=mobile).first()
            # if user:
            #     raise exceptions.ValidationError('该用户已经注册了')
            # code是否正确
            code = cache.get(settings.SMS_CACHE_KEY % {'mobile': mobile})
            if code == code_in or '1234' == code_in:  # 留后门
                # 新建用户
                attrs.pop('code')  # 验证码不是表中的字段，需要pop出来
                return attrs
            else:
                raise exceptions.ValidationError('验证码不合法')

        else:
            raise exceptions.ValidationError('手机号不合法')

    def create(self, validated_data):
        # 密码不是密文
        mobile = validated_data.get('mobile')
        user = models.User.objects.create_user(username=mobile, **validated_data)
        return user
